{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "# 第3章 k近邻法"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "## 习题3.1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "&emsp;&emsp;参照图3.1，在二维空间中给出实例点，画出$k$为1和2时的$k$近邻法构成的空间划分，并对其进行比较，体会$k$值选择与模型复杂度及预测准确率的关系。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "**解答：**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**解答思路：**\n",
    "1. 参照图3.1，使用已给的实例点，采用sklearn的KNeighborsClassifier分类器，对k=1和2时的模型进行训练\n",
    "2. 使用matplotlib的contourf和scatter，画出k为1和2时的k近邻法构成的空间划分\n",
    "3. 根据模型得到的预测结果，计算预测准确率，并设置图形标题\n",
    "4. 根据程序生成的图，比较k为1和2时，k值选择与模型复杂度、预测准确率的关系"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**解答步骤：**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**第1、2、3步：使用已给的实例点，对$k$为1和2时的k近邻模型进行训练，并绘制空间划分**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "from matplotlib.colors import ListedColormap\n",
    "import matplotlib.pyplot as plt\n",
    "from sklearn.neighbors import KNeighborsClassifier\n",
    "import numpy as np\n",
    "%matplotlib inline\n",
    "\n",
    "data = np.array([[5, 12, 1],\n",
    "                 [6, 21, 0],\n",
    "                 [14, 5, 0],\n",
    "                 [16, 10, 0],\n",
    "                 [13, 19, 0],\n",
    "                 [13, 32, 1],\n",
    "                 [17, 27, 1],\n",
    "                 [18, 24, 1],\n",
    "                 [20, 20, 0],\n",
    "                 [23, 14, 1],\n",
    "                 [23, 25, 1],\n",
    "                 [23, 31, 1],\n",
    "                 [26, 8, 0],\n",
    "                 [30, 17, 1],\n",
    "                 [30, 26, 1],\n",
    "                 [34, 8, 0],\n",
    "                 [34, 19, 1],\n",
    "                 [37, 28, 1]])\n",
    "# 得到特征向量\n",
    "X_train = data[:, 0:2]\n",
    "# 得到类别向量\n",
    "y_train = data[:, 2]\n",
    "\n",
    "#（1）使用已给的实例点，采用sklearn的KNeighborsClassifier分类器，\n",
    "# 对k=1和2时的模型进行训练\n",
    "# 分别构造k=1和k=2的k近邻模型\n",
    "models = (KNeighborsClassifier(n_neighbors=1, n_jobs=-1),\n",
    "          KNeighborsClassifier(n_neighbors=2, n_jobs=-1))\n",
    "# 模型训练\n",
    "models = (clf.fit(X_train, y_train) for clf in models)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAABLkAAAHDCAYAAADIusjNAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy88F64QAAAACXBIWXMAAA9hAAAPYQGoP6dpAACm7ElEQVR4nOzdeXgb5bk+/luSZcm2bI/XyI4TK7uzESUhIQFCBGVJylqStrRQUNfTAu0xbaGl7WkFtGw9LebbHmh/5/SgtmE5pS3Q0gJlG3ZDtiGrs09ix5a3ZLxLlq35/SFLtrzFdmyNlvtzXbquaDSSHy+xX93zvO+rU1VVBRERERERERERURzTa10AERERERERERHR2WLIRUREREREREREcY8hFxERERERERERxT2GXEREREREREREFPcYchERERERERERUdxjyEVERERERERERHGPIRcREREREREREcU9hlxERERERERERBT3GHIREREREREREVHcY8hFUeFyuaDT6c7quU1NTWc8V6fT4fbbb5/Qx4l1DocDDodjzOcuWbJkwh8rHr6ODz/8MMrKyhAIBLQuhWLUvn37kJKSgj179mhdChERxTiOVc8ex6qROFZNXmvWrMFdd92ldRlJiyFXAnG73dDpdNi2bVvE8ZaWFqxevRpmsxkvv/zyiM8XRRE6nQ46nQ7bt28f8rjT6YTFYpn0umliamtr4XK5IEmS1qWM289+9jNcc801mDZtGnQ6HVwu17ie39raioceegjf+973oNcP/TWmKArMZjN0Oh32798/SVUnp/b2dvzkJz/Bhg0bkJubC51OB7fbPeL5+/fvx4YNG2CxWJCbm4svfOELaGxsHHJeIBDAww8/jFmzZsFsNuOcc87B008/PeS8559/HmVlZcjOzsbVV1+N2traIedcc801+NrXvjbk+KJFi3DllVfixz/+8fg+aSIimhIcqyaXeB2rVlVV4a677oLdbkdmZiaKiopw5ZVXDvm5HQ3HqtF16NAh3HDDDSgpKUF6ejrKyspw7733orOzM+K8QCCA3/zmN7Db7bBYLJg2bRo2btyI999/P+K8kydP4sorr0RWVhYWLVqEv//970M+5l//+lcUFhaipaVlyGPf+9738F//9V/weDyT+4nSmDDkSnCtra24/PLLsWvXLjz33HPYsGHDmJ433tDhTH70ox+hq6trUl8z2fzrX//Cv/71r/D92tpa3HPPPXE3cACCPw9bt27F8uXLJ/T8//3f/0VPTw8+97nPDfv4s88+C51OB6vViieffPJsSk16TU1NuPfee7F//34sW7Zs1HNrampw0UUX4fDhw7j//vvx3e9+F//4xz9w2WWXobu7O+LcH/7wh/je976Hyy67DL/61a8wc+ZMfP7zn8czzzwTPufo0aP47Gc/i9WrV+PBBx/EwYMH8cUvfjHidV555RW8/fbb+NnPfjZsTV//+tfx3HPP4ciRIxP8ChAR0VTiWDVxJMpY9X/+53/w3//93zj33HPxi1/8At/+9rdx4MABrFmzBq+99tqYXoNj1eiprq7G6tWrUVlZidtvvx0VFRVYu3YtfvKTnwz5+t955534xje+gaVLl+KXv/wlvvOd7+DgwYNYv349Pvroo/B5t9xyC44ePYqHHnoIK1aswKc//WnIshx+3Ov14rvf/S5++tOfIjs7e0hN1157LbKysvDYY49N2edNI0vRugCaOm1tbbjiiisgSRL++te/YuPGjWN6nt1ux4svvogdO3ZgxYoVk1JLSkoKUlIS48eto6MDGRkZUf+4qampUf+YU+XYsWOw2WxoampCQUHBuJ//xBNP4JprroHZbB728S1btuCTn/wkSktL8dRTT+GnP/3p2ZY8JbxeL1JTU4e9whcrioqKUFdXB6vVim3btmHVqlUjnnv//fejo6MD27dvx8yZMwEAq1evxmWXXQa32x3utjp58iR+8Ytf4LbbbsOvf/1rAMBXvvIVrF+/HnfeeSc+/elPw2Aw4F//+hdKSkrw+9//HjqdDgsXLsQll1wCr9cLs9mMnp4e3HHHHfjxj3884s/RpZdeipycHPz+97/HvffeO8lfHSIiOhscq04NjlXPzuc+9zm4XK6IrsAvfelLWLhwIVwuFy699NIzvgbHqtHzxz/+EYqi4N1338XixYsBAF/72tcQCATwhz/8AadPn0ZOTg56enrw+OOPY/PmzfjjH/8Yfv6nP/1pzJ49G08++SRWr16Nrq4uvPHGGxBFERdddBG+/vWv4/3338crr7yCf/u3fwMA/Od//ieys7Pxla98Zdia9Ho9Nm/ejD/84Q+45557JjwVmiYmdn9a6ay0t7djw4YN2LFjB/7yl7/gyiuvHPNzv/nNbyInJ2fMV8heeuklrFu3DhkZGcjMzMSVV16JvXv3Rpwz3DoHXV1d+Na3voX8/HxkZmbimmuuwcmTJ0ecvqYoCpxOJwRBQHZ2Nr74xS8OaUENefLJJ7FgwQKYzWasXLkSb7/99pBzdu7ciY0bNyIrKwsWiwWf+MQnUFlZGXFOqK3+rbfewq233orCwkKUlJQACA7MysvLYbPZYDKZUFhYiMsuuww7duwY8Wu1a9cu6HQ6/O1vfwsf2759O3Q63ZBB2saNG3HeeeeF7w9c50AUxXDY8MUvfjHcuj94Gtm+fftw8cUXIz09HdOnT8fDDz88Ym1n8tOf/hR6vR6/+tWvJvwaITabbcLPPXbsGHbt2jXiAOPEiRN45513cMMNN+CGG27AsWPHhrQgh2zZsgWrV69Geno6cnJycNFFF0VcgQSCP9/r169HZmYmsrKysGrVKjz11FMRn4vT6Rzy2oPXpQhNsXjmmWfwox/9CNOnT0d6ejpaW1tx6tQpfPe738XSpUthsViQlZWFjRs34uOPPx7yul6vFy6XC/Pnz4fZbEZRURGuv/56HDlyBKqqwmaz4dprrx32ednZ2eE/zlVVVThx4sSwX5eBTCYTrFbrGc8DgL/85S+46qqrwgEXEAyZ5s+fjz/96U/hYy+88AL8fj9uvfXW8DGdTodvfOMbqKmpwQcffAAg+DtCEITw747c3Fyoqhq+0v7rX/8avb29+OY3vzliTUajEQ6HAy+88MKYPgciIooOjlU5VgVic6y6cuXKIdNe8/LysG7dujFNLeRYNbpj1dbWVgDAtGnTIo4XFRVBr9eHw1e/34+urq4h5xUWFkKv1yMtLS1ch6qqyMnJARAcowqCEP6/fPLkSTz44IN49NFHRw3/LrvsMhw/fjzuOhkTAUOuBNTR0YGNGzdi69atePbZZ3HVVVeN6/lZWVm444478Pe//33UP4JAMDm/8sorYbFY8NBDD+E//uM/sG/fPlx44YURLZ3DcTqd+NWvfoVPfvKTeOihh5CWljbqAOczn/kM2tra8MADD+Azn/kM3G437rnnniHnvfXWWygvL8dNN92Ee++9F83NzdiwYUPE4tN79+7FunXr8PHHH+Ouu+7Cf/zHf+DYsWNwOBz48MMPh7zmrbfein379uHHP/4xvv/97wMIToN6/PHHsWnTJjz22GP47ne/i7S0tFH/+C1ZsgSCIEQMZN555x3o9Xp8/PHH4V/SgUAA77//Pi666KJhX2fhwoXhrpSvfe1r+OMf/4g//vGPEeefPn0aGzZswLJly/CLX/wCZWVl+N73voeXXnppxPpG8qMf/Qg//vGP8dvf/jYiUGhqahrTzefzjftjjiQ0CBjpyu3TTz+NjIwMXHXVVVi9ejXmzJkzbBv4Pffcgy984QswGo249957cc8992DGjBl44403wue43W5ceeWVOHXqFO6++248+OCDsNvto64Xcib33Xcf/vGPf+C73/0u7r//fqSmpuLo0aN4/vnncdVVV+GXv/wl7rzzTuzevRvr16+PWIOqt7cXV111Fe655x6sXLkSv/jFL/Dv//7vaGlpwZ49e6DT6XDTTTfhpZdewqlTpyI+7t///ne0trbipptuAhD8Gbr55psn/HkMdvLkSTQ0NODcc88d8tjq1auxc+fO8P2dO3ciIyMDCxcuHHJe6HEAWLVqFXbu3Imnn34ax44dw89+9jPMnTsXOTk5aGxsxD333INf/vKXMBqNo9a2cuVK7NmzJ/z/i4iItMWxKseqQPyNVT0eD/Lz8894Hseq0R2rhoK6L3/5y5AkCdXV1fi///s/PP744/jWt74V7mpMS0vDeeedB7fbjSeffBInTpzArl274HQ6kZOTE55xkJOTgzlz5uD+++/HsWPH8OSTT0KSpPA49a677sLGjRtH/NkPWblyJQDgvffeG8NXnSaVSgnjiSeeUAGopaWlqtFoVJ9//vlxPf/NN99UAajPPvusqiiKmpOTo15zzTXhx2+55RY1IyMjfL+trU0VBEH96le/GvE6Ho9Hzc7Ojjj+k5/8RB3447Z9+3YVgFpeXh7xXKfTqQJQf/KTnwx57pe+9KWIcz/1qU+peXl5EccAqADUbdu2hY8dP35cNZvN6qc+9anwseuuu05NTU1Vjxw5Ej5WW1urZmZmqhdddFH4WOhreuGFF6o9PT0RHys7O1u97bbb1PG68sor1dWrV4fvX3/99er111+vGgwG9aWXXlJVVVV37NihAlBfeOGF8Hnr169X169fH76/detWFYD6xBNPDPkY69evVwGof/jDH8LHfD6farVa1U2bNp2xRgDhz+073/mOqtfrVbfbPex5Y7kNV6OqqmpjY+OQ7/eZ/OhHP1IBqG1tbcM+vnTpUvXGG28M3//BD36g5ufnq36/P3zs0KFDql6vVz/1qU+pvb29Ec8PBAKqqqqqoihqZmamet5556ldXV3DnqOqqlpaWqrecsstQ+oY/P0K/f+aPXu22tnZGXGu1+sdUsexY8dUk8mk3nvvveFj//u//6sCUH/5y18O+Xihmg4cOKACUB9//PGIx6+55hrVZrOFzwMQUd9YjPYzF3ps4M9cyJ133qkCUL1er6qqwf8Ds2fPHnJeR0eHCkD9/ve/Hz72rW99K/xzlJubq77xxhuqqqrqV7/6VXXDhg1jqvupp55SAagffvjhmM4nIqKpwbEqx6oDz42HsWrI22+/rep0OvU//uM/zlgbx6rRH6ved999alpaWsT39Ic//OGQ8w4dOqSuWLEi4rzZs2erVVVVEee9/vrrak5OTvic0O+B9957T01LS1NlWR5TXampqeo3vvGNMZ1Lk4edXAmovr4eZrMZM2bMmPBrZGdno7y8HH/7298iOjAGevXVV6EoCj73uc9FXAkxGAw477zz8Oabb474+qGrCwOnKwEYddrR17/+9Yj769atQ3Nz85DujLVr14aTcwCYOXMmrr32Wrzyyivo7e1Fb28v/vWvf+G6667D7Nmzw+cVFRXh85//PN59990hr/nVr34VBoMh4pggCPjwww+H3e1tNOvWrcOOHTvQ0dEBAHj33XfxyU9+Ena7He+88w6A4BUznU6HCy+8cFyvPZDFYglfCQGC6ySsXr0aR48eHdPzVVXF7bffjkcffRRbtmzBLbfcMuScV199dUy3K664YsKfx2DNzc1ISUkZdvekXbt2Yffu3RGLTIZ+Pl955ZXwseeffx6BQAA//vGPh7QZh6YqvPrqq2hra8P3v//9IespnM28+ltuuSXcDh1iMpnCdfT29qK5uRkWiwULFiyIuEL9l7/8Bfn5+cP+PwnVNH/+fJx33nkRVwRPnTqFl156CTfeeGP4PFVVIYrihD+PwUJTCE0m05DHQl+/0DldXV1jOg8AHn30URw/fhwffvghjh8/josvvhiSJOEPf/gDHnnkEbS0tOCmm27C9OnT4XA4hr06HWo3H8vW7kRENPU4VuVYFYifsWpDQwM+//nPY9asWbjrrrvOWBfHqtEfq9psNlx00UX4//6//w9/+ctf8KUvfQn3339/eO3XkMzMTCxevBi33XYb/vrXv+Kxxx5DT08Prrvuuohx4iWXXIITJ06gsrISJ06cwCOPPIJAIIBvfetb+M53voPS0lI8/vjjKCsrw4IFC/Cb3/xm2LpycnI4/tRAYqyuSBF++9vf4tvf/jY2bNiAd955BwsWLJjQ6/z7v/87HnnkEbhcrmHXszl06BCA4C+B4WRlZY342sePH4der8esWbMijs+dO3fE5wxc5wfof+N6+vTpiI81b968Ic+dP38+Ojs70djYCADo7Owc9uuycOFCBAIBVFdXhxcuBDCkTgB4+OGHccstt2DGjBlYuXIlPvnJT+Lmm2+OGIwMZ926dejp6cEHH3yAGTNmoKGhAevWrcPevXsjBg6LFi1Cbm7uqK81mpKSkiF/4HJycrBr164xPf8Pf/gD2tvb8fjjj4+4M8xYFt6Mpi1btiAjIwOzZ8/G4cOHAQSDE5vNhieffDI8xeDIkSPQ6/VYtGjRiK8V2o1vyZIlk1rjcD9LgUAAjz76KB577DEcO3YMvb294cfy8vIialqwYMEZF8a9+eabcfvtt+P48eMoLS3Fs88+C7/fjy984QuT94kMEhoMDdfu7/V6I85JS0sb03khM2fOjPj//61vfQtf//rXUVZWhptuugnV1dV44YUX8Pvf/x5XX301qqqqIr5GqqoCOLsBHxERTR6OVTlWBeJjrNrR0YGrrroKbW1tePfdd4cNrsaDY9WgyRyrPvPMM/ja176GgwcPhteju/766xEIBPC9730Pn/vc55CXl4eenh5ceumlcDgcEeu2XXrppVi8eDF+/vOf46GHHgoft1gsEWvOPfHEE/B4PPj+97+P1157DXfeeSe2bNkCnU6Hz3/+81iwYAEuvvjiiNpUVeX4UwPs5EpAixYtwj//+U90dXXhsssuQ3V19YRe50xXyAKBAIDgWgfDXRGZ7IWeB1+dCgm9gZ1Kg990A8F1F44ePYpf/epXKC4uxs9//nMsXrz4jOsInHvuuTCbzXj77bfxzjvvoLCwEPPnz8e6devw0Ucfwefz4Z133sG6devOquaz/XpdcMEFmDZtGn79618PmTMf4vF4xnSbzC25Q3+k2traIo6rqoqnn34aHR0dWLRoEebNmxe+ybKMF154Ae3t7ZNWR8hIf7gG/vEfaLifpfvvvx/f/va3cdFFF2HLli145ZVX8Oqrr2Lx4sXh/2fjccMNN8BoNIavkG3ZsgXnnnvuhN9EjEVRUREAoK6ubshjdXV1yM3NDXdvFRUVwePxDPlZDD23uLh4xI/zf//3f9i/fz9cLhd6e3vxpz/9Cffccw/OPfdcPPzww6ipqRmyKO/p06cBYEzraBAR0dTjWHXycaw6+WPV7u5uXH/99di1axdeeOGFMYdJHKue2WSOVR977DEsX748HHCFXHPNNejs7Az/bnj77bexZ88eXHPNNRHnzZs3DwsXLhx17azW1lb88Ic/xIMPPoiMjAw8/fTT2Lx5M6677jpce+212Lx587DrqimKwvGnBtjJlaBWr16N559/HldeeSUuu+wyvPPOOygoKBj365SXl6OiogL33HMPBEGIeGzOnDkAgjtSjPcqSWlpKQKBAI4dOxZxNSt0ReNshK7aDXTw4EGkp6eHvwbp6ek4cODAkPOqqqqg1+vH3D5fVFSEW2+9FbfeeisaGhqwYsUK/OxnPxt1C+xQK/Y777yDmTNnhgcI69atg8/nw5NPPon6+vozLmY41VcF5s6di4cffhgOhwMbNmzA66+/jszMzIhzQsHGmTzxxBPD7uoyEWVlZQCCO9ecc8454eNvvfUWampqcO+99w5Z0Pz06dP42te+hueffx433XQT5syZg0AggH379sFutw/7cUI/33v27Bn1qm1OTg4URRly/Pjx42e8Uhry5z//GRdffDF+97vfRRwf/Idxzpw5+PDDD+H3+0ddbD03NxdXXnklnnzySdx444147733UFFRMaZaJmr69OkoKCjAtm3bhjz20UcfRXyd7XY7/ud//gf79++PuEIZWkh3pO9JZ2cn7rzzTtx3330QBAH19fXw+/3hUCwtLQ05OTk4efJkxPOOHTsGvV6P+fPnn+VnSUREk4Vj1Ugcq47fVI5VA4EAbr75Zrz++uv405/+hPXr14+5Lo5VoztWra+vD3dNDuT3+wEAPT094fOA4cM9v98fPm849957L2bNmoUbb7wRAFBbW4vly5eHHy8uLh6yi+LJkyfR3d095HtNU4+dXAnsE5/4BJ5++mkcPnwYGzZsmNDOYqErZC+88MKQ/7hXXHEFsrKycP/994d/iQwUarceTmje+2OPPRZx/Gy3/AWADz74IGJueGgq0+WXXw6DwQCDwYDLL78cL7zwQsSuOvX19Xjqqadw4YUXjtq+DgR/Oba0tEQcKywsRHFx8Zh2Z1m3bh0+/PBDvPnmm+GBQ35+PhYuXBhukz3T1bHQTiHD/dGaLOeccw7++c9/Yv/+/bj66quHXOXSYk2utWvXAsCQMCXU/n3nnXdi8+bNEbevfvWrmDdvXvgKy3XXXQe9Xo977713yNWn0NXDyy+/HJmZmXjggQfC0+gGnwME/5hXVlaiu7s7fOzFF18c11Vpg8Ew5Krls88+OySs2bRpE5qamoasLzC4JgD4whe+gH379uHOO++EwWDADTfcEPH4WLdlHo9NmzYN+dxff/11HDx4EJ/+9KfDx6699loYjcaI//+qquI3v/kNpk+fjvPPP3/Y13/ooYeQk5ODr371qwCCV0pTUlJQVVUFILjmVmNjI6xWa8Tztm/fjsWLFyM7O3vSPlciIjp7HKsGcaw6cVM1Vv3mN7+J//u//8Njjz2G66+/flw1cawa3bHq/PnzsXPnThw8eDDi+NNPPw29Xh8OGkMXO5955pmI83bs2IEDBw5EhFYDHTx4EL/+9a/x6KOPhoPbadOmhcefALB///5hx58ARhzX0tRhJ1eC+9SnPoX//u//xpe+9CVcc801ePnll4csTHgmofUOPv744/AfKyC4jsHjjz+OL3zhC1ixYgVuuOEGFBQU4MSJE/jHP/6BCy64YNhfcEBwS9VNmzahoqICzc3NWLNmDd56663wL6ezufKzZMkSXHHFFfjWt74Fk8kUHpwM3ML5pz/9KV599VVceOGFuPXWW5GSkoLf/va38Pl8ePjhh8/4Mdra2lBSUoLNmzdj2bJlsFgseO2117B161b84he/OOPz161bh5/97Georq6OGCBcdNFF+O1vfwubzTak5XawOXPmQBAE/OY3v0FmZiYyMjJw3nnnDTuP/mysWbMGL7zwAj75yU9i8+bNeP7558NXZia6zsEf//hHHD9+HJ2dnQCC7cM//elPAQT/4JWWlo743NmzZ2PJkiV47bXX8KUvfQlAcB2ov/zlL7jssstG/Pm+5ppr8Oijj6KhoQFz587FD3/4Q9x3331Yt24drr/+ephMJmzduhXFxcV44IEHkJWVhUceeQRf+cpXsGrVKnz+859HTk4OPv74Y3R2duL3v/89AOArX/kK/vznP2PDhg34zGc+gyNHjmDLli3hq2tjcdVVV+Hee+/FF7/4RZx//vnYvXs3nnzyySFX126++Wb84Q9/wLe//W189NFHWLduHTo6OvDaa6/h1ltvxbXXXhs+98orr0ReXh6effZZbNy4EYWFhRGvtXDhQqxfv35MC3r++te/hqIo4YVr//73v6OmpgZAcBAYCo9+8IMf4Nlnn8XFF1+Mf//3f0d7ezt+/vOfY+nSpfjiF78Yfr2SkhKUl5fj5z//Ofx+P1atWoXnn38e77zzDp588slhpy+cOHECP//5z/GPf/wj/HhKSgquvfZalJeX48SJE3juuedQXFwcHlwCwStzb7311pCFg4mIKDZwrMqx6tma7LFqRUUFHnvsMaxduxbp6enYsmVLxOOf+tSnIn7OBuNYNbpj1TvvvBMvvfQS1q1bh9tvvx15eXl48cUX8dJLL+ErX/lKuON/5cqVuOyyy/D73/8era2tuPzyy1FXV4df/epXSEtLQ3l5+bCvf8cdd+Czn/0sVq9eHT62efNmXHvttfjBD34AIDg2fvHFFyOe9+qrr2LmzJkjhmc0haK5lSNNrdAWwlu3bh3y2H/+53+qANSrrroqYnvagQZuyzxYaGvkgdsyD3zeFVdcoWZnZ6tms1mdM2eO6nQ6I7ZGHrwts6qqakdHh3rbbbepubm5qsViUa+77rrwlrIPPvjgkOc2NjYO+/keO3YsfAx92wlv2bJFnTdvnmoymdTly5erb7755pC6d+zYoV5xxRWqxWJR09PT1Ysvvlh9//33h/0Yg7+mPp9PvfPOO9Vly5apmZmZakZGhrps2TL1scceG/qFHUZra6tqMBjUzMzMiO2et2zZogJQv/CFLwx5zuBtflVVVV944QV10aJFakpKSsT2x+vXr1cXL1485DVuueUWtbS09Iz1hb6Ogz9WSkqK+tnPfnbIFsLjFdo2erjbcN+rwX75y1+qFoslvL3xX/7yFxWA+rvf/W7E54iiqAJQH3300fCx//3f/1WXL1+umkwmNScnR12/fr366quvRjzvb3/7m3r++eeraWlpalZWlrp69Wr16aefjjjnF7/4hTp9+nTVZDKpF1xwgbpt27YRt2Ue7v+X1+tVv/Od76hFRUVqWlqaesEFF6gffPDBsN/zzs5O9Yc//KE6a9Ys1Wg0qlarVd28eXPEFuMht956qwpAfeqpp4Y8hnFsy1xaWjri92vg/z9VVdU9e/aol19+uZqenq4KgqDeeOONqsfjGfKavb296v3336+Wlpaqqamp6uLFi9UtW7aMWMOnP/1p9frrrx9yvL6+Xr366qvVzMxMdcWKFRG/d1RVVV966SUVgHro0KExfa5ERDR1OFblWDUexqq33HLLiOOe4cY+w+FYNbpj1Q8//FDduHGjarVaVaPRqM6fP1/92c9+NuR3SWdnp3rvvfeqixYtUtPS0tTs7Gz1qquuUnfu3Dns6/7jH/9QLRaLWltbO+SxBx54QC0uLlaLiorUhx56KOKx3t5etaioSP3Rj340pvppculUNQorIRKNkSRJWL58ObZs2RKe80w0WEtLC2bPno2HH34YX/7yl7UuJ2bdcccd+N3vfgePx4P09HSty9HEddddB51Oh+eee07rUoiIKAFwrEpjwbHq2CTqWPX555/H5z//eRw5cmTM68LR5OGaXKSZ4XYxqaiogF6vP+NClpTcsrOzcdddd+HnP//5hHZ0SQZerxdbtmzBpk2bEmrQMB779+/Hiy++iPvuu0/rUoiIKA5xrEoTxbHqmSXyWPWhhx7C7bffzoBLI+zkIs3cc8892L59Oy6++GKkpKTgpZdewksvvYSvfe1r+O1vf6t1eURxqaGhAa+99hr+/Oc/4/nnn8eOHTtG3JWHiIiIRsaxKtHk41iVphoXnifNnH/++Xj11Vdx3333ob29HTNnzoTL5cIPf/hDrUsjilv79u3DjTfeiMLCQvy///f/OGggIiKaII5ViSYfx6o01djJRUREREREREREcY9rchERERERERERUdxjyEVERERERERERHEv5tbkCgQCqK2tRWZmJnQ6ndblEBERJS1VVdHW1obi4mLo9bwuRsmH41IiIqLYMNZxacyFXLW1tZgxY4bWZRAREVGf6upqlJSUaF0GUdRxXEpERBRbzjQujbmQKzMzEwBwx5/ugCndpHE1REREycvX6cMjn3kk/LeZKNmEfvar77gDWabYG5c+sOsxPDnfi5ZsM5ZOW4p1M9dpXRIREdGUGOu4NOZCrlAruCndBFNG7A0miIiIkg2naVGyCv3sZ5lMsRlyrboDJqkC7jIv9rTsQUpjChw2h9ZlERERTZkzjUu5wAYRERERUZxy2cvhrDJDMAtal0JERKQ5hlxERERERERERBT3Ym66IiUvVVVxuvY0mqub0dvTC1OGCdY5VqRlpWldGhEREVFsUxTIkLWuImGoqorWxlY0yo3o6e6B0WzEtNnTYMm1aF0aERGNgiEXxYT2U+3Y9cYu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",
      "text/plain": [
       "<Figure size 1500x500 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 设置图形标题\n",
    "titles = ('K Neighbors with k=1',\n",
    "          'K Neighbors with k=2')\n",
    "\n",
    "# 设置图形的大小和图间距\n",
    "fig = plt.figure(figsize=(15, 5))\n",
    "plt.subplots_adjust(wspace=0.4, hspace=0.4)\n",
    "\n",
    "# 分别获取第1个和第2个特征向量\n",
    "X0, X1 = X_train[:, 0], X_train[:, 1]\n",
    "\n",
    "# 得到坐标轴的最小值和最大值\n",
    "x_min, x_max = X0.min() - 1, X0.max() + 1\n",
    "y_min, y_max = X1.min() - 1, X1.max() + 1\n",
    "\n",
    "# 构造网格点坐标矩阵\n",
    "# 设置0.2的目的是生成更多的网格点，数值越小，划分空间之间的分隔线越清晰\n",
    "xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.2),\n",
    "                     np.arange(y_min, y_max, 0.2))\n",
    "\n",
    "for clf, title, ax in zip(models, titles, fig.subplots(1, 2).flatten()):\n",
    "    # （2）使用matplotlib的contourf和scatter，画出k为1和2时的k近邻法构成的空间划分\n",
    "    # 对所有网格点进行预测\n",
    "    Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])\n",
    "    Z = Z.reshape(xx.shape)\n",
    "    # 设置颜色列表\n",
    "    colors = ('red', 'green', 'lightgreen', 'gray', 'cyan')\n",
    "    # 根据类别数生成颜色\n",
    "    cmap = ListedColormap(colors[:len(np.unique(Z))])\n",
    "    # 绘制分隔线，contourf函数用于绘制等高线，alpha表示颜色的透明度，一般设置成0.5\n",
    "    ax.contourf(xx, yy, Z, cmap=cmap, alpha=0.5)\n",
    "\n",
    "    # 绘制样本点\n",
    "    ax.scatter(X0, X1, c=y_train, s=50, edgecolors='k', cmap=cmap, alpha=0.5)\n",
    "\n",
    "    # （3）根据模型得到的预测结果，计算预测准确率，并设置图形标题\n",
    "    # 计算预测准确率\n",
    "    acc = clf.score(X_train, y_train)\n",
    "    # 设置标题\n",
    "    ax.set_title(title + ' (Accuracy: %d%%)' % (acc * 100))\n",
    "\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> **补充知识：**   \n",
    "np.meshgrid方法：用于构造网格点坐标矩阵，可参考https://blog.csdn.net/lllxxq141592654/article/details/81532855"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**第4步：比较$k$为1和2时，k值选择与模型复杂度、预测准确率的关系**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "1. $k$值选择与模型复杂度的关系  \n",
    "&emsp;&emsp;根据书中第3.2.3节$k$值的选择：\n",
    "  > &emsp;&emsp;如果选择较小的$k$值，就相当于用较小的邻域中的训练实例进行预测，“学习”的近似误差会减小，只有与输入实例较近的（相似的）训练实例才会对预测结果起作用。$k$值的减小就意味着整体模型变得复杂，容易发生过拟合。  \n",
    "  > &emsp;&emsp;如果选择较大的$k$值，就相当于用较大邻域中的训练实例进行预测。$k$值的增大就意味着整体的模型变得简单。\n",
    "\n",
    "  &emsp;&emsp;综上所属，$k$值越大，模型复杂度越低，模型越简单，容易发生欠拟合。反之，$k$值越小，模型越复杂，容易发生过拟合。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "  \n",
    "  \n",
    "2. $k$值选择与预测准确率的关系  \n",
    "&emsp;&emsp;从图中观察到，当$k=1$时，模型易产生过拟合，当$k=2$时准确率仅有88%，故在过拟合发生前，$k$值越大，预测准确率越低，也反映模型泛化能力越差，模型简单。反之，$k$值越小，预测准确率越高，模型具有更好的泛化能力，模型复杂。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 习题3.2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "&emsp;&emsp;利用例题3.2构造的$kd$树求点$x=(3,4.5)^T$的最近邻点。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**解答：**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**解答思路：**  "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**方法一：**\n",
    "1. 使用sklearn的KDTree类，结合例题3.2构建平衡$kd$树，配置相关参数（构建平衡树kd树算法，见书中第54页算法3.2内容）；\n",
    "2. 使用tree.query方法，查找(3, 4.5)的最近邻点（搜索kd树算法，见书中第55页第3.3.2节内容）；\n",
    "3. 根据第3步返回的参数，得到最近邻点。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**方法二：**  \n",
    "&emsp;&emsp;根据书中第3章算法3.3用$kd$树的最近邻搜索方法，查找(3, 4.5)的最近邻点"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**解答步骤：**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**方法一：**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "x点(3,4.5)的最近邻点是(2, 3)\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "from sklearn.neighbors import KDTree\n",
    "\n",
    "# 构造例题3.2的数据集\n",
    "train_data = np.array([[2, 3],\n",
    "                       [5, 4],\n",
    "                       [9, 6],\n",
    "                       [4, 7],\n",
    "                       [8, 1],\n",
    "                       [7, 2]])\n",
    "# （1）使用sklearn的KDTree类，构建平衡kd树\n",
    "# 设置leaf_size为2，表示平衡树\n",
    "tree = KDTree(train_data, leaf_size=2)\n",
    "\n",
    "# （2）使用tree.query方法，设置k=1，查找(3, 4.5)的最近邻点\n",
    "# dist表示与最近邻点的距离，ind表示最近邻点在train_data的位置\n",
    "dist, ind = tree.query(np.array([[3, 4.5]]), k=1)\n",
    "node_index = ind[0]\n",
    "\n",
    "# （3）得到最近邻点\n",
    "x1 = train_data[node_index][0][0]\n",
    "x2 = train_data[node_index][0][1]\n",
    "print(\"x点(3,4.5)的最近邻点是({0}, {1})\".format(x1, x2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "可得到点$x=(3,4.5)^T$的最近邻点是$(2,3)^T$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**方法二：** "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "1. 首先找到点$x=(3,4.5)^T$所在领域的叶节点$x_1=(4,7)^T$，则最近邻点一定在以$x$为圆心，$x$到$x_1$距离为半径的圆内；\n",
    "2. 找到$x_1$的父节点$x_2=(5,4)^T$，$x_2$的另一子节点为$x_3=(2,3)^T$，此时$x_3$在圆内，故$x_3$为最新的最近邻点，并形成以$x$为圆心，以$x$到$x_3$距离为半径的圆；\n",
    "3. 继续探索$x_2$的父节点$x_4=(7,2)^T$,$x_4$的另一个子节点$(9,6)$对应的区域不与圆相交，故不存在最近邻点，所以最近邻点为$x_3=(2,3)^T$。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "可得到点$x=(3,4.5)^T$的最近邻点是$(2,3)^T$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 习题3.3"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "&emsp;&emsp;参照算法3.3，写出输出为$x$的$k$近邻的算法。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**解答：**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**解答思路：**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "1. 参考书中第3章算法3.3（用$kd$树的最近邻搜索），写出输出为$x$的$k$近邻算法；\n",
    "2. 根据算法步骤，写出算法代码，并用习题3.2的解进行验证。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**解答步骤：**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**第1步：用$kd$树的$k$邻近搜索算法**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "根据书中第3章算法3.3：\n",
    "> **算法3.3 用$kd$树的最近邻搜索**  \n",
    "> 输入：已构造的kd树；目标点$x$；    \n",
    "输出：$x$的k近邻    \n",
    "（1）在$kd$树中找出包含目标点$x$的叶结点：从根结点出发，递归地向下访问树。若目标点$x$当前维的坐标小于切分点的坐标，则移动到左子结点，否则移动到右子结点，直到子结点为叶结点为止；  \n",
    "（2）如果“当前$k$近邻点集”元素数量小于$k$或者叶节点距离小于“当前$k$近邻点集”中最远点距离，那么将叶节点插入“当前k近邻点集”；  \n",
    "（3）递归地向上回退，在每个结点进行以下操作：  \n",
    "&emsp;&emsp;（a）如果“当前$k$近邻点集”元素数量小于$k$或者当前节点距离小于“当前$k$近邻点集”中最远点距离，那么将该节点插入“当前$k$近邻点集”。  \n",
    "&emsp;&emsp;（b）检查另一子结点对应的区域是否与以目标点为球心、以目标点与“当前$k$近邻点集”中最远点间的距离为半径的超球体相交。  \n",
    "&emsp;&emsp;如果相交，可能在另一个子结点对应的区域内存在距目标点更近的点，移动到另一个子结点，接着，递归地进行近邻搜索；  \n",
    "&emsp;&emsp;如果不相交，向上回退；  \n",
    "（4）当回退到根结点时，搜索结束，最后的“当前$k$近邻点集”即为$x$的近邻点。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**第2步：根据算法步骤，写出算法代码，并用习题3.2的解进行验证**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "import json\n",
    "\n",
    "\n",
    "class Node:\n",
    "    \"\"\"节点类\"\"\"\n",
    "\n",
    "    def __init__(self, value, index, left_child, right_child):\n",
    "        self.value = value.tolist()\n",
    "        self.index = index\n",
    "        self.left_child = left_child\n",
    "        self.right_child = right_child\n",
    "\n",
    "    def __repr__(self):\n",
    "        return json.dumps(self, indent=3, default=lambda obj: obj.__dict__, ensure_ascii=False, allow_nan=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "class KDTree:\n",
    "    \"\"\"kd tree类\"\"\"\n",
    "\n",
    "    def __init__(self, data):\n",
    "        # 数据集\n",
    "        self.data = np.asarray(data)\n",
    "        # kd树\n",
    "        self.kd_tree = None\n",
    "        # 创建平衡kd树\n",
    "        self._create_kd_tree(data)\n",
    "\n",
    "    def _split_sub_tree(self, data, depth=0):\n",
    "        # 算法3.2第3步：直到子区域没有实例存在时停止\n",
    "        if len(data) == 0:\n",
    "            return None\n",
    "        # 算法3.2第2步：选择切分坐标轴, 从0开始（书中是从1开始）\n",
    "        l = depth % data.shape[1]\n",
    "        # 对数据进行排序\n",
    "        data = data[data[:, l].argsort()]\n",
    "        # 算法3.2第1步：将所有实例坐标的中位数作为切分点\n",
    "        median_index = data.shape[0] // 2\n",
    "        # 获取结点在数据集中的位置\n",
    "        node_index = [i for i, v in enumerate(\n",
    "            self.data) if list(v) == list(data[median_index])]\n",
    "        return Node(\n",
    "            # 本结点\n",
    "            value=data[median_index],\n",
    "            # 本结点在数据集中的位置\n",
    "            index=node_index[0],\n",
    "            # 左子结点\n",
    "            left_child=self._split_sub_tree(data[:median_index], depth + 1),\n",
    "            # 右子结点\n",
    "            right_child=self._split_sub_tree(\n",
    "                data[median_index + 1:], depth + 1)\n",
    "        )\n",
    "\n",
    "    def _create_kd_tree(self, X):\n",
    "        self.kd_tree = self._split_sub_tree(X)\n",
    "\n",
    "    def query(self, data, k=1):\n",
    "        data = np.asarray(data)\n",
    "        hits = self._search(data, self.kd_tree, k=k, k_neighbors_sets=list())\n",
    "        dd = np.array([hit[0] for hit in hits])\n",
    "        ii = np.array([hit[1] for hit in hits])\n",
    "        return dd, ii\n",
    "\n",
    "    def __repr__(self):\n",
    "        return str(self.kd_tree)\n",
    "\n",
    "    @staticmethod\n",
    "    def _cal_node_distance(node1, node2):\n",
    "        \"\"\"计算两个结点之间的距离\"\"\"\n",
    "        return np.sqrt(np.sum(np.square(node1 - node2)))\n",
    "\n",
    "    def _search(self, point, tree=None, k=1, k_neighbors_sets=None, depth=0):\n",
    "        n = point.shape[1]\n",
    "        if k_neighbors_sets is None:\n",
    "            k_neighbors_sets = []\n",
    "        if tree is None:\n",
    "            return k_neighbors_sets\n",
    "\n",
    "        # (1)找到包含目标点x的叶节点\n",
    "        if tree.left_child is None and tree.right_child is None:\n",
    "            # 更新当前k近邻集\n",
    "            return self._update_k_neighbor_sets(k_neighbors_sets, k, tree, point)\n",
    "\n",
    "        # 递归地向下访问kd树\n",
    "        if point[0][depth % n] < tree.value[depth % n]:\n",
    "            direct = 'left'\n",
    "            next_branch = tree.left_child\n",
    "        else:\n",
    "            direct = 'right'\n",
    "            next_branch = tree.right_child\n",
    "\n",
    "        if next_branch is not None:\n",
    "            # (3)(b)检查另一子节点对应的区域是否相交\n",
    "            k_neighbors_sets = self._search(point, tree=next_branch, k=k, depth=depth + 1,\n",
    "                                            k_neighbors_sets=k_neighbors_sets)\n",
    "            # 计算目标点与切分点形成的分割超平面的距离\n",
    "            temp_dist = abs(tree.value[depth % n] - point[0][depth % n])\n",
    "\n",
    "            # 判断超球体是否与超平面相交\n",
    "            if not (k_neighbors_sets[0][0] < temp_dist and len(k_neighbors_sets) == k):  # 换到另一侧\n",
    "                # 如果相交，递归地进行近邻搜索\n",
    "                # (3)(a)判断当前结点，并更新当前k近邻点集\n",
    "                k_neighbors_sets = self._update_k_neighbor_sets(k_neighbors_sets, k, tree, point)  # tree 返回父节点\n",
    "                if direct == 'left':\n",
    "                    return self._search(point, tree=tree.right_child, k=k, depth=depth + 1,\n",
    "                                        k_neighbors_sets=k_neighbors_sets)\n",
    "                else:\n",
    "                    return self._search(point, tree=tree.left_child, k=k, depth=depth + 1,\n",
    "                                        k_neighbors_sets=k_neighbors_sets)\n",
    "        else:\n",
    "            # 如果选定的子树为空，则直接判断是否需要回溯另一侧子树\n",
    "            # 如果 k 近邻集合未满，则需要回溯另一侧子树\n",
    "            if len(k_neighbors_sets) < k:\n",
    "                # 如果相交，递归地进行近邻搜索\n",
    "                # (3)(a)判断当前结点，并更新当前k近邻点集\n",
    "                k_neighbors_sets = self._update_k_neighbor_sets(k_neighbors_sets, k, tree, point)  # tree 返回父节点\n",
    "                if direct == 'left':\n",
    "                    return self._search(point, tree=tree.right_child, k=k, depth=depth + 1,\n",
    "                                        k_neighbors_sets=k_neighbors_sets)\n",
    "                else:\n",
    "                    return self._search(point, tree=tree.left_child, k=k, depth=depth + 1,\n",
    "                                        k_neighbors_sets=k_neighbors_sets)\n",
    "\n",
    "        return k_neighbors_sets\n",
    "\n",
    "    def _update_k_neighbor_sets(self, best, k, tree, point):\n",
    "        # 计算目标点与当前结点的距离\n",
    "        node_distance = self._cal_node_distance(point, tree.value)\n",
    "        if len(best) == 0:\n",
    "            best.append((node_distance, tree.index, tree.value))\n",
    "        elif len(best) < k:\n",
    "            # 如果“当前k近邻点集”元素数量小于k\n",
    "            self._insert_k_neighbor_sets(best, tree, node_distance)\n",
    "        else:\n",
    "            # 叶节点距离小于“当前 𝑘 近邻点集”中最远点距离\n",
    "            if best[0][0] > node_distance:\n",
    "                best = best[1:]\n",
    "                self._insert_k_neighbor_sets(best, tree, node_distance)\n",
    "        return best\n",
    "\n",
    "    @staticmethod\n",
    "    def _insert_k_neighbor_sets(best, tree, node_distance):\n",
    "        \"\"\"将距离最远的结点排在前面\"\"\"\n",
    "        n = len(best)\n",
    "        for i, item in enumerate(best):\n",
    "            if item[0] < node_distance:\n",
    "                # 将距离最远的结点插入到前面\n",
    "                best.insert(i, (node_distance, tree.index, tree.value))\n",
    "                break\n",
    "        if len(best) == n:\n",
    "            best.append((node_distance, tree.index, tree.value))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 打印信息\n",
    "def print_k_neighbor_sets(k, ii, dd):\n",
    "    if k == 1:\n",
    "        text = \"x点的最近邻点是\"\n",
    "    else:\n",
    "        text = \"x点的%d个近邻点是\" % k\n",
    "\n",
    "    for i, index in enumerate(ii):\n",
    "        res = X_train[index]\n",
    "        if i == 0:\n",
    "            text += str(tuple(res))\n",
    "        else:\n",
    "            text += \", \" + str(tuple(res))\n",
    "\n",
    "    if k == 1:\n",
    "        text += \"，距离是\"\n",
    "    else:\n",
    "        text += \"，距离分别是\"\n",
    "    for i, dist in enumerate(dd):\n",
    "        if i == 0:\n",
    "            text += \"%.4f\" % dist\n",
    "        else:\n",
    "            text += \", %.4f\" % dist\n",
    "\n",
    "    print(text)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "x点的最近邻点是(2, 3)，距离是1.8028\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "\n",
    "X_train = np.array([[2, 3],\n",
    "                    [5, 4],\n",
    "                    [9, 6],\n",
    "                    [4, 7],\n",
    "                    [8, 1],\n",
    "                    [7, 2]])\n",
    "kd_tree = KDTree(X_train)\n",
    "# 设置k值\n",
    "k = 1\n",
    "# 查找邻近的结点\n",
    "dists, indices = kd_tree.query(np.array([[3, 4.5]]), k=k)\n",
    "# 打印邻近结点\n",
    "print_k_neighbor_sets(k, indices, dists)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{\n",
       "   \"value\": [\n",
       "      7,\n",
       "      2\n",
       "   ],\n",
       "   \"index\": 5,\n",
       "   \"left_child\": {\n",
       "      \"value\": [\n",
       "         5,\n",
       "         4\n",
       "      ],\n",
       "      \"index\": 1,\n",
       "      \"left_child\": {\n",
       "         \"value\": [\n",
       "            2,\n",
       "            3\n",
       "         ],\n",
       "         \"index\": 0,\n",
       "         \"left_child\": null,\n",
       "         \"right_child\": null\n",
       "      },\n",
       "      \"right_child\": {\n",
       "         \"value\": [\n",
       "            4,\n",
       "            7\n",
       "         ],\n",
       "         \"index\": 3,\n",
       "         \"left_child\": null,\n",
       "         \"right_child\": null\n",
       "      }\n",
       "   },\n",
       "   \"right_child\": {\n",
       "      \"value\": [\n",
       "         9,\n",
       "         6\n",
       "      ],\n",
       "      \"index\": 2,\n",
       "      \"left_child\": {\n",
       "         \"value\": [\n",
       "            8,\n",
       "            1\n",
       "         ],\n",
       "         \"index\": 4,\n",
       "         \"left_child\": null,\n",
       "         \"right_child\": null\n",
       "      },\n",
       "      \"right_child\": null\n",
       "   }\n",
       "}"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 打印kd树\n",
    "kd_tree"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "&emsp;&emsp;上述打印的平衡kd树和书中第55页的图3.4 kd树示例一致。\n",
    "\n",
    "![3-1-KD-Tree-Demo.png](../images/3-1-KD-Tree-Demo.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "更换数据集，使用更高维度的数据，并设置$k=3$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "x点的3个近邻点是(4, 7, 4), (5, 4, 4), (2, 3, 4)，距离分别是2.6926, 2.0616, 1.8028\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "\n",
    "X_train = np.array([[2, 3, 4],\n",
    "                    [5, 4, 4],\n",
    "                    [9, 6, 4],\n",
    "                    [4, 7, 4],\n",
    "                    [8, 1, 4],\n",
    "                    [7, 2, 4]])\n",
    "kd_tree = KDTree(X_train)\n",
    "# 设置k值\n",
    "k = 3\n",
    "# 查找邻近的结点\n",
    "dists, indices = kd_tree.query(np.array([[3, 4.5, 4]]), k=k)\n",
    "# 打印邻近结点\n",
    "print_k_neighbor_sets(k, indices, dists)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.5"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
